library IEEE;
use IEEE.std_logic_1164.all;

entity TxUnit is
  port (
    clk, reset : in std_logic;
    enable : in std_logic;
    ld : in std_logic;
    txd : out std_logic;
    regE : out std_logic;
    bufE : out std_logic;
    data : in std_logic_vector(7 downto 0));
end TxUnit;

architecture archTxUnit of TxUnit is

	type state is (nothing, load_buffE, load_regE, debut, donnee, fin);
	
	signal bufEtmp : std_logic;
	signal regEtmp : std_logic;
	signal etat : state := nothing;
	signal bufferE : std_logic_vector(7 downto 0);
	signal registreE : std_logic_vector(7 downto 0);
begin
	process (clk, reset)
		variable cpt : integer range -1 to 7 := 0;
	begin
	    if (reset = '0') then
			etat <= nothing;
			-- booleens pour connaitre l'etat du registre et du buffer
			bufEtmp <= '1';
			regEtmp <= '1';
			txd <= '1';
			cpt := 7;
		-- faut peut etre réagir sur front descendant de clk
		-- pour que le enable = 1 soit detecté sans un top d'horloge
		-- en retard 
		elsif (clk = '1' and clk'event) then
	        case etat is
		        when nothing =>
	            	if(ld = '1') then
						etat <= load_buffE;
						-- buffer plein
						bufEtmp <= '0';
						bufferE <= data;
					end if;

				when load_buffE =>
					etat <= load_regE;
					-- buffer vide
					bufEtmp <= '1';
					-- registre plein
					regEtmp <= '0';
					registreE <= bufferE;
					-- on est pas obligé de vider le buffer
					-- il suffit juste de dire qu'il est ecrasable
					-- mais pour les besoins du test on le fait
					-- bufferE <= (others => '0');

				when load_regE =>
					etat <= debut;
					if ld = '1' then
						-- buffer plein
						bufEtmp <= '0';
						bufferE <= data;
					end if;

				when debut =>
					if (enable = '1') then
						cpt := 7;
						etat <= donnee;
						-- bit de start
						txd <= '0';
					end if;
					if (ld = '1') then
						bufEtmp <= '0';
						bufferE <= data;
					end if;

				when donnee =>
					if (ld = '1') then
						--buffer plein
						bufEtmp <= '0';
						bufferE <= data;
					end if;
					if (enable = '1') then
						if (cpt = -1) then
							etat <= fin;
							cpt := 7;
							regEtmp <= '1';
							-- envoi du bit de parite
							txd <= registreE(7) xor registreE(6) xor registreE(5) xor registreE(4) xor registreE(3) xor registreE(2) xor registreE(1) xor registreE(0);
						else
						-- envoi du bit cpt
							txd <= registreE(cpt);
							cpt := cpt - 1;
						end if;
					end if;

				when fin =>				
					if (enable = '1') then
						-- envoi du bit de stop
						txd <= '1';
						
						if (bufEtmp = '0') then
						-- le buffer n'est pas vide, ilf faut envoyer une deuxième donnée
						-- sans passer par l'état initial
							etat <= load_regE;
							registreE <= bufferE;
							-- bufferE <= (others => '0');
							bufEtmp <= '1';
							regEtmp <= '0';
						else
							etat <= nothing;							
						end if;
					end if;
			end case;
		end if;
		bufE <= bufEtmp;
		regE <= regEtmp;
	end process;
end archTxUnit;
